#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gtk/gtk.h>
#include "mEdit_callbacks.h"
#include "mEdit_interface.h"
#include "fpp.h"

extern void settime();
extern int calcmarkerctgpos();
extern void deletemarker();
extern void refreshlist();
extern void displaymarker();
extern GtkWidget *markerEditWindow;
extern void markersinctgcount();
extern void updateproj();

void
on_help_ok_clicked(GtkButton       *button,
                                        gpointer         user_data)
{
gtk_widget_destroy(gtk_widget_get_toplevel(GTK_WIDGET(button)));
}

void
on_pickClonesToggle_toggled            (GtkToggleButton *togglebutton,
                                        gpointer         user_data)
{
editmarkerstatus= !editmarkerstatus;
}


void
on_probe1_activate                     (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markPROBE;
}


void
on_sts1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markSTS;
}


void
on_end1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markEND;
}


void
on_epcr1_activate                      (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markPCR;
}


void
on_snp1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markSNP;
}


void
on_yac1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markYAC;
}


void
on_bac1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markBAC;
}


void
on_pac1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markPAC;
}


void
on_cdna1_activate                      (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markCDNA;
}


void
on_cosmid1_activate                    (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markCOSMID;
}


void
on_fosmid1_activate                    (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markFOSMID;
}


void
on_locus1_activate                     (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markLOCUS;
}


void
on_clone1_activate                     (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markCLONE;

}


void
on_ebac1_activate                      (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markeBAC;
}


void
on_emrk1_activate                      (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markeMRK;
}


void
on_tc1_activate                        (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markTC;
}


void
on_ssr1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markSSR;
}


void
on_rflp1_activate                      (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markRFLP;
}


void
on_overgo1_activate                    (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markOVERGO;
}


void
on_rep1_activate                       (GtkMenuItem     *menuitem,
                                        int *type)
{
*type=markREP;
}

/*                     DEF: destroy_edit_marker_callback
 * Handler for the 'destroy' signal for the marker edit window*/
void
destroy_edit_marker_callback(GtkWidget *widget, gpointer data){
  active -= EDITMARKER;
  editmarkerstatus=0;
  markerEditWindow = 0;
}

void
on_cancelButton_clicked                (GtkButton       *button,
                                        GtkWidget *window)
{
  gtk_widget_destroy(window);
}

/* Read through cloneList, check if marker already
   attached to clone.  If not, update modified date.  Next, go through clones
   attached to marker.  If not present in cloneList, updated modified date.
*/
void update_dates(struct markerclone *cloneList, int marker_index){
   MARKER *marker;
   CLONE *clone;
   struct markerclone *newclp, *oldclp;
   int found;

   marker = arrp(markerdata,marker_index,MARKER);

   /* Check for added clones*/
   for(newclp=cloneList; newclp!=NULL; newclp=newclp->nextclone){
      found=0;
      if(newclp->cloneindex == marker->cloneindex) found=1;
      for(oldclp=marker->nextclone; (oldclp!=NULL) && !found; oldclp=oldclp->nextclone){
         if(newclp->cloneindex == oldclp->cloneindex) found=1;
      }
      if(!found){
         clone = arrp(acedata,newclp->cloneindex,CLONE);
         settime(&clone->modified_date);
      }
   }

   /* Check for deleted clones*/
   found=0;
   for(newclp=cloneList; (newclp!=NULL) && !found; newclp=newclp->nextclone){
      if(marker->cloneindex == newclp->cloneindex) found=1;
   }
   if(!found){
      clone = arrp(acedata,marker->cloneindex,CLONE);
      settime(&clone->modified_date);
   }
   for(oldclp=marker->nextclone; oldclp!=NULL; oldclp=oldclp->nextclone){
      found=0;
      for(newclp=cloneList; (newclp!=NULL) && !found; newclp=newclp->nextclone){
         if(oldclp->cloneindex == newclp->cloneindex) found=1;
      }
      if(!found){
         clone = arrp(acedata,oldclp->cloneindex,CLONE);
         settime(&clone->modified_date);
      }
   }
}

/* Read through clonesText, find valid clones, see if clones in fpc.
   if so, put them in cloneList struct, which is returned to user.
*/
struct markerclone *get_clones_from_text(gchar *clonesText){
   char curClone[CLONE_SZ+1];
   struct markerclone *cloneList=NULL, *ptr, *lastPtr=NULL;
   int i,j;
   int index;

   /* Add last newline if needed*/
   if(clonesText[strlen(clonesText)-1]!='\n')
      strcat(clonesText,"\n");
   /* Build a list of clones in text box*/
   for(i=0,j=0;i<strlen(clonesText);i++){
      if(clonesText[i]=='\n'){
         curClone[j]='\0';
         j=0;
         if(strlen(curClone) == 0) continue;
         if(fppFind(acedata,curClone,&index,cloneOrder)){
            ptr=messalloc(sizeof(struct markerclone));
            ptr->cloneindex=index;
            ptr->nextclone=NULL;
            if(cloneList==NULL)
               cloneList=ptr;
            else
               lastPtr->nextclone=ptr;
            lastPtr=ptr;
         }
         else{
            printf("ERROR -- Clone %s not found in FPC; Entry ignored.\n",curClone);
         }
      }
      else if((clonesText[i]==' ') || (clonesText[i]=='\t')){
         continue;
      }
      else{
         curClone[j++]=clonesText[i];
         if(j>CLONE_SZ){
            curClone[j-1]='\0';
            printf("WARNING -- Clone name (%s...) may not be longer than %d characters; Entry ignored\n",
                   curClone, CLONE_SZ);
            while(clonesText[i]!='\n')
               i++;
            j=0;
         }
      }
   }
   return cloneList;
}

void detach_marker_from_clone(int marker_index, int clone_index){
   CLONE *clone;
   struct markertop *ptr, *prev=NULL;

   clone = arrp(acedata,clone_index,CLONE);
   for(ptr=clone->marker; ptr!=NULL; ptr=ptr->nextmarker){
      if(ptr->markerindex == marker_index){
         if(prev==NULL)
            clone->marker=ptr->nextmarker;
         else
            prev->nextmarker=ptr->nextmarker;
         messfree(ptr);
         break;
      }
      prev=ptr;
   }
}

int attach_clone_to_marker(int marker_index, int clone_index){
   CLONE *clone;
   MARKER *marker;
   int found;
   struct markerclone *clp;

   marker = arrp(markerdata,marker_index,MARKER);
   clone = arrp(acedata,clone_index,CLONE);
   if(clone_index==marker->cloneindex){
      printf("WARNING -- %s listed more than once.  Multiples ignored\n",clone->clone);
      return 0;
   }
   if(marker->cloneindex==-1){ 
      marker->cloneindex=clone_index;
   }
   else if(marker->nextclone==NULL){ 
      marker->nextclone = messalloc(sizeof(struct markerclone));
      marker->nextclone->cloneindex=clone_index;
      marker->nextclone->weak=0;
      marker->nextclone->nextclone=NULL;
   }
   else{
      found=0;
      for (clp = marker->nextclone; clp->nextclone != NULL; clp = clp->nextclone){
         if(clone_index==clp->cloneindex){   /*Check for duplicates*/
            printf("WARNING -- %s listed more than once.  Multiples ignored\n",clone->clone);
            found=1;
            break;
         }
      }
      if(!found && (clone_index==clp->cloneindex)){   /*Check for duplicates*/
         printf("WARNING -- %s listed more than once.  Multiples ignored\n",clone->clone);
         found=1;
      }
      if(!found){
         clp->nextclone = messalloc(sizeof(struct markerclone));
         clp->nextclone->cloneindex=clone_index;
         clp->nextclone->weak=0;
         clp->nextclone->nextclone=NULL;
      }
   }
   return 1;
}

void attach_marker_to_clone(int clone_index, int marker_index){
   CLONE *clone;
   MARKER *marker;
   struct markertop *mp, *prev=NULL;

   clone = arrp(acedata,clone_index,CLONE);
   for(mp=clone->marker;mp!=NULL;mp=mp->nextmarker){
      if(mp->markerindex==marker_index) return;   /*Marker already attached*/
      prev=mp;
   }
   marker = arrp(markerdata,marker_index,MARKER);
   if(prev==NULL){
      clone->marker = messalloc(sizeof(struct markertop));
      clone->marker->markerindex=marker_index;
      clone->marker->weak=0;
      clone->marker->new=1;
      strcpy(clone->marker->marker,marker->marker);
      clone->marker->nextmarker=NULL;
   }
   else{
      prev->nextmarker = messalloc(sizeof(struct markertop));
      prev->nextmarker->markerindex=marker_index;
      prev->nextmarker->weak=0;
      prev->nextmarker->new=1;
      strcpy(prev->nextmarker->marker,marker->marker);
      prev->nextmarker->nextmarker=NULL;
   } 
}

void update_contigs_list(int marker_index){
   CLONE *clone;
   MARKER *marker;
   struct markerctgpos *ctglist, *prev=NULL;
   int found;
   struct markerclone *clp;

   marker = arrp(markerdata,marker_index,MARKER);

   /*Clear old contigs list*/
   ctglist = marker->pos;
   while(ctglist!=NULL){
      prev = ctglist;
      ctglist=ctglist->next;
      messfree(prev);
   }
   marker->pos=NULL;

   /*Add first clone ctg*/
   clone = arrp(acedata,marker->cloneindex,CLONE);
   if(clone==NULL) return;
   marker->pos = messalloc(sizeof(struct markerctgpos));
   marker->pos->ctg = clone->ctg;
   marker->pos->pos =  calcmarkerctgpos(marker->pos,marker_index);
   marker->pos->next = NULL;

   /*Add remaining clone ctgs*/
   clp=marker->nextclone;
   while(clp!=NULL){
      clone = arrp(acedata,clp->cloneindex,CLONE);
      ctglist=marker->pos;
      found=0;
      while((ctglist!=NULL) && (!found)){
         if(ctglist->ctg == clone->ctg) found=1;
         prev=ctglist;
         ctglist=ctglist->next;
      }
      if(!found){
         prev->next=messalloc(sizeof(struct markerctgpos));
         prev->next->ctg=clone->ctg;
         prev->next->pos =  calcmarkerctgpos(prev->next,marker_index);
         prev->next->next=NULL;
      }
      clp=clp->nextclone;
   }
}

void
on_applyButton_clicked                 (GtkButton       *button,
                                        struct tempMarkerInfo  *tempMk)
{
gchar *clonesText;
gchar *remarksText;
MARKER *marker;
char curRemark[COMMENT_SZ+1];
int i,j;
struct markerclone *clp, *prevPtr, *cloneList;
struct remark *rmp, *prevRemPtr, *tempRemark;
GtkTextBuffer* buffer;
GtkTextIter it1,it2;

update=1;

marker = arrp(markerdata,tempMk->marker_index,MARKER);

buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(clonesTextview));
gtk_text_buffer_get_bounds(buffer,&it1,&it2);
clonesText = gtk_text_buffer_get_text(buffer,&it1,&it2,TRUE);

buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(remarksTextview));
gtk_text_buffer_get_bounds(buffer,&it1,&it2);
remarksText = gtk_text_buffer_get_text(buffer,&it1,&it2,TRUE);
 
/* Check if clonesText is empty */
for(i=0,j=0;i<strlen(clonesText);i++){
   if ((clonesText[i]!=0) && (clonesText[i]!=' ') && (clonesText[i]!='\t') && (clonesText[i]!='\n'))
      break;
}
if(i==strlen(clonesText)){
   if(messQuery("Removing the last clone from the marker will also delete the marker. Is this okay?")){
      /*Remove marker*/
      printf("Delete marker %s\n",marker->marker);
      gtk_widget_destroy(gtk_widget_get_toplevel(GTK_WIDGET(button)));
      graphDestroy();
      deletemarker(tempMk->marker_index);
      if (graphActivate(g7)) graphDestroy();
      refreshlist();
      if (graphExists(g2))
      {
         displaykeyset(1);
      }
      markersinctgcount();
      updateproj();
      newctg=TRUE;
      ctgdisplay(currentctg);
      if (graphActivate(gmarkerpopup)) graphDestroy();

   }
   return;
}

cloneList = get_clones_from_text(clonesText);

if(cloneList!=NULL){
   update_dates(cloneList, tempMk->marker_index);
   /* Replace old clone attachments with new; start by removing all.*/
   prevPtr=NULL;
   for (clp=marker->nextclone; clp != NULL; clp = clp->nextclone){
      detach_marker_from_clone(tempMk->marker_index, clp->cloneindex);
      if(prevPtr!=NULL) messfree(prevPtr);
      prevPtr=clp;
   }
   if(prevPtr!=NULL) messfree(prevPtr);

   detach_marker_from_clone(tempMk->marker_index, marker->cloneindex);
   marker->cloneindex=-1;             /*Start fresh*/
   marker->nextclone=NULL;

   for(clp=cloneList; clp!=NULL; clp=clp->nextclone){
      if(!attach_clone_to_marker(tempMk->marker_index, clp->cloneindex)) continue;
      attach_marker_to_clone(clp->cloneindex, tempMk->marker_index);
   }
}
else{ /*If the user entered junk/only nonexisting clones*/
   printf("No valid clones entered.\n");
   return;
}

/*Replace old Remark attachments with new*/
tempRemark=marker->remark;   /*Keep in case of error followed by cancel*/
marker->remark=NULL;         /*Start fresh -- Will be freed later*/
/* WMN 3/21/05 added the overall strlen check to avoid crash */
if (strlen(remarksText) > 0) {
    for(i=0,j=0;i <= strlen(remarksText);i++){
       if(remarksText[i]=='\n' || remarksText[i]== 0){
          curRemark[j]='\0';
          j=0;
          if(strlen(curRemark) == 0) continue;
          if(marker->remark==NULL){ 
             marker->remark = messalloc(sizeof(struct remark));
             strcpy(marker->remark->message, curRemark);
             marker->remark->next=NULL;
          }
          else{
             for (rmp = marker->remark; rmp->next != NULL; rmp = rmp->next)
                ;
             rmp->next = messalloc(sizeof(struct remark));
             strcpy(rmp->next->message, curRemark);
             rmp->next->next=NULL;
          }
       }
       else{
          curRemark[j++]=remarksText[i];
          if(j>COMMENT_SZ){
             curRemark[j-1]='\0';
             printf("ERROR -- Remark (%s...) must be shorter than %d characters.\n",curRemark, COMMENT_SZ);
             marker->remark=tempRemark;
             return;
          }
       }
    }
}

/*Fill in new type*/
marker->type=tempMk->type;

/*Update contigs list*/
update_contigs_list(tempMk->marker_index);

/*Free old remark attachments; they have been replaced with new*/
prevRemPtr=NULL;
for (rmp=tempRemark; rmp != NULL; rmp = rmp->next){
   if(prevRemPtr!=NULL) messfree(prevRemPtr);
   prevRemPtr=rmp;
}
if(prevRemPtr!=NULL) messfree(prevRemPtr);

gtk_widget_destroy(gtk_widget_get_toplevel(GTK_WIDGET(button)));
/* fred 3/4/04 -- done in destroy function now
active -= EDITMARKER;
editmarkerstatus=0;
*/
settime(&marker->modified_date);
displaymarker(tempMk->marker_index);  /*Refresh*/
displayclone(clonedisplayed);
newctg=TRUE;
ctgdisplay(currentctg);
g_free(clonesText);
g_free(remarksText);
}
